﻿
/*
///    This file is part of BannerLib4Net.
///
///    BannerLib4Net is free software: you can redistribute it and/or modify
///    it under the terms of the GNU General Public License as published by
///    the Free Software Foundation, either version 3 of the License, or
///    (at your option) any later version.

///    BannerLib4Net is distributed in the hope that it will be useful,
///    but WITHOUT ANY WARRANTY; without even the implied warranty of
///    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
///    GNU General Public License for more details.
///
///    You should have received a copy of the GNU General Public License
///    along with BannerLib4Net.  If not, see <http://www.gnu.org/licenses/>.
*/



using System;
using System.Data;
using System.IO;
using BannerLib4Net.Data.Configuration;
using NAnt.Core;
using NAnt.Core.Attributes;
using BannerLib4Net.Core.Extensions;
using BannerLib4Net.Data;
using BannerLib4Net.Postgresql;
using NAnt.Core.Types;

namespace BannerLib4Net.Build.Nant.Tasks
{
    [TaskName("PostgresqlScriptTask")]
    public class PostgresqlScriptRunnerTask: Task
    {
        private const int DEFAULT_PORT = 5432;
        private const string DEFAULT_DELIMITER = ";";

        ///<summary>
        ///Constructs the Task and assigns a default port
        ///</summary>
        public PostgresqlScriptRunnerTask()
        {
            this.Port = PostgresqlScriptRunnerTask.DEFAULT_PORT;
            this.Delimiter = PostgresqlScriptRunnerTask.DEFAULT_DELIMITER;
        }

        ///<summary>
        ///Target Server
        ///</summary>
        [TaskAttribute("server", Required = true)]
        [StringValidator(AllowEmpty = false)]
        public virtual string Server { get; set; }

        ///<summary>
        ///Server Password
        ///</summary>	
        [TaskAttribute("password", Required = true)]
        [StringValidator(AllowEmpty = false)]
        public virtual string Password { get; set; }

        ///<summary>
        ///Server User
        ///</summary>	
        [TaskAttribute("user", Required = true)]
        [StringValidator(AllowEmpty = false)]
        public virtual string User { get; set; }

        ///<summary>
        ///Server Database
        ///</summary>	
        [TaskAttribute("database", Required = true)]
        [StringValidator(AllowEmpty = false)]
        public virtual string Database { get; set; }

        ///<summary>
        ///Server Port
        ///</summary>
        [TaskAttribute("port", Required = false)]
        [Int32ValidatorAttribute(MinValue = 0, MaxValue = 65534)]
        public virtual Int32 Port { get; set; }

        ///<summary>
        ///Server Timeout
        ///</summary>
        [TaskAttribute("timeout", Required = false)]
        [Int32ValidatorAttribute(MinValue = 0, MaxValue = 60000)]
        public virtual Int32? Timeout { get; set; }


        /// <summary>
        /// The character that delimits scripts statements in the file
        /// </summary>
        [TaskAttribute("delimiter", Required = false)]
        public virtual string Delimiter { get; set; }

        /// <summary>
        /// The Fileset containing the scripts to execute
        /// </summary>
        [BuildElement("fileset", Required = true)]
        public virtual FileSet SQLFileSet { get; set; }



        /// <summary>
        /// Executes the PostgreSQL scripts in the targeted Fileset
        /// </summary>
        protected override void ExecuteTask()
        {
            Connection cn = null;

            try
            {

                String contents = string.Empty;

                Log(Level.Info, String.Format("Executing PostgreSQL Task with the following connection string: {0}", this.ConnectionSettings.ToConnectionString()));

                cn = new Connection(this.ConnectionSettings.ToConnectionString());

                if (this.SQLFileSet != null && this.SQLFileSet.FileNames.Count > 0)
                {
                    foreach (String sqlFile in SQLFileSet.FileNames)
                    {

                        if (File.Exists(sqlFile))
                        {

                            contents = File.ReadAllText(sqlFile);


                            if (this.Delimiter.Length > 0)
                            {
                                if (contents.Split(Char.Parse(this.Delimiter)).Length > 0)
                                {
                                    String[] statements = contents.Split(Char.Parse(this.Delimiter));

                                    Log(Level.Info, String.Format("Executing {0} Statement(s) ", statements.Length));

                                    for (int i = 0; i < statements.Length; i++)
                                    {
                                        if (statements[i].Trim().Length > 1)
                                        {
                                            Log(Level.Info, "Executing Statement: " + statements[i]);
                                            cn.ExecuteStatement(statements[i].StripCarriageReturns());
                                        }
                                    }
                                }
                                else
                                {
                                    Log(Level.Info, "Executing Statement: " + contents);
                                    cn.ExecuteStatement(contents.StripCarriageReturns());
                                }
                            }
                            else
                            {
                                Log(Level.Info, "Executing Statement: " + contents);
                                cn.ExecuteStatement(contents.StripCarriageReturns());
                            }
                        }
                    }
                }
                else
                {
                    Log(Level.Info, "No SQL files to run ... ");
                }
            }
            catch (BuildException ex)
            {

				Log(Level.Error, String.Format("Exception thrown while trying to execute statment"));
				Log(Level.Error, String.Format("Exception Message: {0}", ex.Message));
				Log(Level.Error, String.Format("Exception Source: {0}", ex.Source));
				Log(Level.Error, String.Format("Exception StackTrace: {0}", ex.StackTrace));

                if (FailOnError)
                    throw ex;
            }
            finally
            {
                if (cn != null)
                {
                    if (cn.State == ConnectionState.Open)
                    {
                        cn.Close();
                        cn.Dispose();
                    }
                }
            }
        }

        private ConnectionSettings ConnectionSettings
        {
            get
            {
                ConnectionSettings settings = new ConnectionSettings();

                settings.Database = this.Database;
                settings.Debug = this.Verbose;
                settings.Password = this.Password;
                settings.Port = this.Port;
                settings.Server = this.Server;
                settings.User = this.User;
                settings.Timeout = this.Timeout;

                return settings;
            }
        }

        /// <summary>
        /// Logs an infomation message to the build
        /// </summary>
        /// <param name="Message">String representing the message to be logged</param>
        private void LogInfoMessage(String Message)
        {
            if (this.Verbose)
            {
                Log(Level.Info, Message);
            }
        }

    }
}
